home *** CD-ROM | disk | FTP | other *** search
- /*
- * LRBug.c
- *
- * Try to work around what seems to be a hardware bug of CyberstormPPC
- * 604e/233 cards.
- *
- * Written by Emmanuel Lesueur lesueur@club-internet.fr
- *
- * This code is in the public domain. You can do whatever you want with it.
- *
- *
- * CLI Usage:
- * LRBug NOREQ/S,QUIET/S,NOWAIT/S
- *
- * NOREQ: don't ask before attempting to restart a task.
- * QUIET: don't write messages with kprinf() when restarting a task.
- * NOWAIT: don't install a handler, just restart crashed tasks and quit.
- *
- * WB Usage:
- * Tooltypes NOREQ, QUIET, and NOWAIT, with the same meaning.
- *
- * To remove the handler, send a CTRL-C.
- *
- *
- * Object:
- * Install an exception handler to catch exceptions caused by a
- * corrupted LR (bit 0 or 2 incorrectly set). When one is caught,
- * clear the bad bit and restart the task.
- *
- * Issue:
- * Unfortunately, I don't know of any way to fall back to the default
- * exception handler for exceptions that are not of the "bad LR" type. So
- * in that case, I just display a small message via kprintf() and let the
- * user run PPCShowTrap to get the full register/MMU/stack dump.
- *
- *
- * To compile with SAS/C 6.58:
- * sc resetopts cpu=68040 params=registers nostackcheck optimize
- * optimizesize link stripdebug nostartup lib lib:debug.lib LRBug.c
- *
- * To compile with gcc:
- * gcc -o LRBug -O2 -m68040 -nostdlib LRBug.c -ldebug
- *
- * To compile with vbcc:
- * vc -o LRBug -O2 -cpu=68040 -nostdlib LRBug.c -lamiga -lppc -ldebug
- *
- * Others:
- * I don't know, but: SHOULD BE LINKED WITH NO STARTUP !
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <exec/ports.h>
- #include <dos/dos.h>
- #include <intuition/intuition.h>
- #include <workbench/startup.h>
- #include <powerup/ppclib/ppc.h>
- #include <powerup/ppclib/tasks.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <proto/intuition.h>
- #include <proto/icon.h>
- #include <powerup/proto/ppc.h>
-
- #ifdef __SASC
- # define SAVEDS __saveds
- # define ASM __asm
- # define REG(x,y) register __##x y
- #elif defined(__GNUC__)
- # define SAVEDS
- # define ASM
- # define REG(x,y) y __asm__(#x)
- #elif defined(_DCC)
- # define SAVEDS __geta4
- # define ASM
- # define REG(x,y) __##x y
- #elif defined(__STORM__)
- # define SAVEDS __saveds
- # define ASM
- # define REG(x,y) register __##x y
- #elif defined(__VBCC__)
- # define SAVEDS
- # define ASM
- # define REG(x,y) __reg(#x) y
- #else
- # error add #defines for your compiler...
- #endif
-
- typedef BOOL ASM hook_func(REG(a0,struct Hook* h),
- REG(a2,void* t),
- REG(a1,struct ExceptionMsg* em));
-
- static void* maintask;
- static struct Hook* oldhook;
- static BOOL noreq,quiet;
-
- struct Library* PPCLibBase;
- struct ExecBase *SysBase;
- struct IntuitionBase *IntuitionBase;
- struct DosLibrary *DOSBase;
- struct Library *IconBase;
-
- void kprintf(const char*,...);
-
- void install_handler(void);
- void scan_tasks_list(void);
-
- /*
- * Program entry point. No startup code needed.
- */
- int SAVEDS start(void) {
- struct Process *proc;
- struct WBStartup *wbmsg=NULL;
- int ret=RETURN_FAIL;
-
- SysBase=*(struct ExecBase**)4;
- proc=(struct Process*)FindTask(NULL);
- if(!proc->pr_CLI) {
- WaitPort(&proc->pr_MsgPort);
- wbmsg=(struct WBStartup*)GetMsg(&proc->pr_MsgPort);
- }
-
- if((DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",36)) &&
- (IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",39))) {
- if(PPCLibBase=OpenLibrary("ppc.library",46)) {
- maintask=FindTask(NULL);
-
- if(proc->pr_CLI) {
- struct RDArgs *rda;
- LONG args[3]={0,0,0};
-
- if(rda=ReadArgs("NOREQ/S,QUIET/S,NOWAIT/S",args,NULL)) {
- ret=RETURN_OK;
- noreq=args[0];
- quiet=args[1];
- if(args[2])
- scan_tasks_list();
- else
- install_handler();
- FreeArgs(rda);
- } else
- PrintFault(IoErr(),"Error: ");
- } else {
- BPTR olddir=CurrentDir(wbmsg->sm_ArgList[0].wa_Lock);
- struct DiskObject *dob;
- if(IconBase=OpenLibrary("icon.library",36)) {
- if(dob=GetDiskObjectNew(wbmsg->sm_ArgList[0].wa_Name)) {
- ret=RETURN_OK;
- noreq=dob->do_ToolTypes &&
- FindToolType((UBYTE **)dob->do_ToolTypes,
- (UBYTE *)"NOREQ");
- quiet=dob->do_ToolTypes &&
- FindToolType((UBYTE **)dob->do_ToolTypes,
- (UBYTE *)"QUIET");
- if(dob->do_ToolTypes &&
- FindToolType((UBYTE **)dob->do_ToolTypes,
- (UBYTE *)"NOWAIT"))
- scan_tasks_list();
- else
- install_handler();
- FreeDiskObject(dob);
- }
- CloseLibrary(IconBase);
- }
- CurrentDir(olddir);
- }
-
- CloseLibrary((struct Library*)PPCLibBase);
- } else
- Printf("Can't open ppc.library V46\n");
- }
- CloseLibrary((struct Library*)IntuitionBase);
- CloseLibrary((struct Library*)DOSBase);
-
- if(wbmsg) {
- Forbid();
- ReplyMsg(&wbmsg->sm_Message);
- }
- return ret;
- }
-
- /*
- * Exception hook:
- * - If the exception looks like one caused by the LR bug (i.e.
- * PC==LR and bit 0 or 2 of LR set), signal our main task.
- * - otherwise, if there was an old exception hook, call it.
- * - otherwise, if the exception is a real one (not a kernel message),
- * kprintf a message to signal it to the user. I'd like to
- * fall back to the default handling (showing regs, stack, ...),
- * but I don't think it's possible. One can always use
- * PPCShowTrap to display those informations, anyway.
- */
- BOOL SAVEDS ASM exception_func(REG(a0,struct Hook* h),
- REG(a2,void* task),
- REG(a1,struct ExceptionMsg* em)) {
- if(em->Type==EXCEPTION_DATAACCESS &&
- em->SRR0==em->LR &&
- ((em->LR&0xf0000000)==0x20000000 ||
- (em->LR&0xf0000000)==0x80000000)) {
- /*
- * This hook is called with task==NULL, so we don't know
- * which task to restart. To work around that problem,
- * the main task will scan the tasks list and retrieve
- * it by checking LR's. No need to save the exception message.
- */
- Signal(maintask,SIGBREAKF_CTRL_F);
- return TRUE;
- } else if(oldhook) {
- return ((hook_func*)oldhook->h_Entry)(oldhook,task,em);
- } else {
- if(!(em->Type&EXCEPTION_MSG))
- kprintf("Exception %lx. Use PPCShowTrap for details.\n",em->Type);
- return FALSE;
- }
- }
-
- static struct Hook hook={{NULL,NULL},(ULONG (*)())exception_func};
-
- /*
- * Restart a task.
- */
- void restart(void* task,ULONG lr) {
- PPCSetTaskAttrsTags(task,
- PPCTASKINFOTAG_PC,&lr,
- PPCTASKINFOTAG_LR,&lr,
- TAG_END);
- PPCStartTaskTags(task,PPCTASKSTARTTAG_RUN,TRUE,TAG_END);
- }
-
- /*
- * Task list scanning hook. Look for tasks that have bad PC/LR,
- * and restart them.
- */
- void SAVEDS ASM scantasks_func(REG(a2,void* task)) {
- ULONG pc,lr,state;
- state=PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_STATE,NULL,TAG_END);
- PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_PC,&pc,TAG_END);
- PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_LR,&lr,TAG_END);
- if(state==TS_WAIT && pc==lr &&
- ((lr&0xf0000000)==0x20000000 || (lr&0xf0000000)==0x80000000)) {
- static struct EasyStruct es={
- sizeof(struct EasyStruct),0,"LRBug Exception Handler",
- "LR bug caught in task\n\"%s\"",
- "Continue|Suspend",
- };
- const char* name=(const char*)PPCGetTaskAttrsTags(task,
- PPCTASKINFOTAG_NAME,NULL,
- TAG_END);
- if(!quiet)
- kprintf("LR bug caught in task \"%s\" (%lx).\n",name,task);
- lr&=~0xf0000000;
- if(noreq)
- restart(task,lr);
- else {
- if(EasyRequest(NULL,&es,NULL,name)==1)
- restart(task,lr);
- }
-
- }
- }
-
- void scan_tasks_list(void) {
- static struct Hook scantasks_hook={{NULL,NULL},(ULONG (*)())scantasks_func};
-
- PPCGetTaskAttrsTags(NULL,
- PPCTASKINFOTAG_HOOK,&scantasks_hook,
- PPCTASKINFOTAG_ALLTASK,TRUE,
- TAG_END);
- }
-
- /*
- * Install the exception handler and wait for events.
- */
-
- void install_handler(void) {
- oldhook=(struct Hook *)PPCGetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,NULL,TAG_END);
- PPCSetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,&hook,TAG_END);
-
- while(!(Wait(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_F)&SIGBREAKF_CTRL_C))
- scan_tasks_list();
-
- PPCSetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,oldhook,TAG_END);
- }
-
-